client_id <- readLines("spotify_client_id.txt")
## Warning in readLines("spotify_client_id.txt"): incomplete final line found on
## 'spotify_client_id.txt'
client_secret <- readLines("spotify_client_secret.txt")
## Warning in readLines("spotify_client_secret.txt"): incomplete final line found
## on 'spotify_client_secret.txt'
get_spotify_token <- function(client_id, client_secret) {
resp <- request("https://accounts.spotify.com/api/token") |>
req_auth_basic(client_id, client_secret) |>
req_body_form(grant_type = "client_credentials") |>
req_method("POST") |>
req_perform()
resp_body_json(resp)$access_token
}
token <- get_spotify_token(client_id, client_secret)
get_artists_data <- function(artist_ids, token) {
artist_chunks <- split(artist_ids, ceiling(seq_along(artist_ids) / 50))
map_dfr(artist_chunks, function(ids_chunk) {
req <- request("https://api.spotify.com/v1/artists") |>
req_url_query(ids = paste(ids_chunk, collapse = ",")) |>
req_headers(Authorization = paste("Bearer", token))
resp <- req_perform(req)
content <- resp_body_json(resp, simplifyVector = FALSE)
map_dfr(content$artists, function(artist) {
tibble(
artist_id = artist$id,
artist_name = artist$name,
genres = paste(artist$genres, collapse = ", "),
popularity = artist$popularity,
followers = artist$followers$total,
artist_url = artist$external_urls$spotify
)
})
})
}
get_artist_top_tracks <- function(artist_id, token) {
url <- paste0("https://api.spotify.com/v1/artists/", artist_id, "/top-tracks?market=US")
req <- request(url) |>
req_headers(Authorization = paste("Bearer", token))
resp <- req_perform(req)
content <- resp_body_json(resp, simplifyVector = FALSE)
map_dfr(content$tracks, function(track) {
tibble(
track_name = track$name,
album_name = track$album$name,
popularity = track$popularity,
track_duration_ms = track$duration_ms,
explicit = track$explicit,
artist_id = artist_id
)
})
}
artist_ids <- c(
"06HL4z0CvFAxyc27GXpf02", # Taylor Swift
"1Xyo4u8uXC1ZmMpatF05PJ", # The Weeknd
"4q3ewBCX7sLwd24euuV69X", # Bad Bunny
"3TVXtAsR1Inumwj472S9r4", # Drake
"6qqNVTkY8uBg9cP3Jd7DAH", # Billie Eilish
"0Y5tJX1MQlPlqiwlOH1tJY", # Travis Scott
"12GqGscKJx3aE4t07u7eVZ", # Peso Pluma
"5K4W6rqBFWDnAN6FQUkS6x", # Kanye West
"66CXWjxzNUsdJxJ2JdwvnR", # Ariana Grande
"2LRoIwlKmHjgvigdNGBHNo" # Feid
)
artists_data <- get_artists_data(artist_ids, token)
all_tracks <- map_dfr(artist_ids, get_artist_top_tracks, token = token)
# Merge track data with artist names
all_tracks <- left_join(all_tracks, artists_data |> select(artist_id, artist_name), by = "artist_id")
top10_tracks <- all_tracks |>
arrange(desc(popularity))
datatable(top10_tracks |>
select(Track = track_name,
Artist = artist_name,
Popularity = popularity,
Explicit = explicit))
# Collecting IDs for Top Albums from 2018 to 2024
album_ids_2018 <- c(
"1ATL5GLyefJaxhQzSPVrLX", # Scorpion - Drake
"6trNtQUgC8cgbWcqoMYkOR", # beerbons & bentleys - Post Malone
"2Ti79nwTsont5ZHfdxIzAm", # ? - XXXTENTACION
"2vlhlrgMaXqcnhRqIEV9AP", # Dua Lipa - Dua Lipa
"3T4tUhGYeRNVUGevb0wThu" # ÷ - Ed Sheeran
)
album_ids_2019 <- c(
"0S0KGZnfBGSIssfF54WSJh", # WHEN WE ALL FALL ASLEEP, WHERE DO WE GO? – Billie Eilish
"4g1ZRSobMefqF6nelkgibi", # Hollywood’s Bleeding – Post Malone
"2fYhqwDWXjbpjaIJPEfKFw", # thank u, next – Ariana Grande
"3oIFxDIo2fwuk4lwCmFZCx", # No.6 Collaborations Project – Ed Sheeran
"0xzScN8P3hQAz3BT3YYX5w" # Shawn Mendes – Shawn Mendes
)
album_ids_2020 <- c(
"5lJqux7orBlA1QzyiBGti1", # YHLQMDLG - Bad Bunny
"4yP0hdKOZPNshxUOjY0cZj", # After Hours - The Weeknd
"4g1ZRSobMefqF6nelkgibi", # Hollywood's Bleeding - Post Malone
"7xV2TzoaVc0ycW7fwBwAml", # Fine Line - Harry Styles
"7fJJK56U9fHixgO0HQkhtI" # Future Nostalgia - Dua Lipa
)
album_ids_2021 <- c(
"6s84u2TUpR3wdUv4NgKA2j", # SOUR - Olivia Rodrigo
"7fJJK56U9fHixgO0HQkhtI", # Future Nostalgia - Dua Lipa
"5dGWwsZ9iB2Xc3UKR0gif2", # Justice - Justin Bieber
"32iAEBstCjauDhyKpGjTuq", # = - Ed Sheeran
"4XLPYMERZZaBzkJg0mkdvO" # Planet Her - Doja Cat
)
album_ids_2022 <- c(
"3RQQmkQEvNCY4prGKE6oc5", # Un Verano Sin Ti - Bad Bunny
"5r36AJ6VOJtp00oxSkBZ5h", # Harry's House - Harry Styles
"6s84u2TUpR3wdUv4NgKA2j", # SOUR - Olivia Rodrigo
"32iAEBstCjauDhyKpGjTuq", # = - Ed Sheeran
"4XLPYMERZZaBzkJg0mkdvO" # Planet Her - Doja Cat
)
album_ids_2023 <- c(
"3RQQmkQEvNCY4prGKE6oc5", # Un Verano Sin Ti - Bad Bunny
"151w1FgRZfnKZA9FEcg9Z3", # Midnights - Taylor Swift
"07w0rG5TETcyihsEIZR3qG", # SOS - SZA
"2ODvWsOgouMbaA5xf0RkJe", # Starboy - The Weeknd
"4kS7bSuU0Jm9LYMosFU2x5", # MAÑANA SERÁ BONITO - KAROL G
"6i7mF7whyRJuLJ4ogbH2wh", # One Thing at a Time - Morgan Wallen
"1NAmidJlEaVgA3MpcPFYGq", # Lover - Taylor Swift
"7txGsnDSqVMoRl6RQ9XyZP", # HEROES & VILLAINS - Metro Boomin
"4jox3ip1I39DFC2B7R5qLH", # GÉNESIS - Peso Pluma
"5r36AJ6VOJtp00oxSkBZ5h" # Harry's House - Harry Styles
)
album_ids_2024 <- c(
"5H7ixXZfsNMGbIE5OBSpcb", # THE TORTURED POETS DEPARTMENT: THE ANTHOLOGY - Taylor Swift
"7aJuG4TFXa2hmE4z1yxc3n", # HIT ME HARD AND SOFT - Billie Eilish
"3iPSVi54hsacKKl1xIR2eH", # Short n’ Sweet - Sabrina Carpenter
"4kS7bSuU0Jm9LYMosFU2x5", # MAÑANA SERÁ BONITO - Karol G
"5EYKrEDnKhhcNxGedaRQeK", # eternal sunshine - Ariana Grande
"64LU4c1nfjz1t4VnGhagcg", # 1989 (Taylor’s Version) - Taylor Swift
"07w0rG5TETcyihsEIZR3qG", # SOS - SZA
"1NAmidJlEaVgA3MpcPFYGq", # Lover - Taylor Swift
"168CdR21lfn0TTyw1Pkdcm", # Fireworks & Rollerblades - Benson Boone
"2ODvWsOgouMbaA5xf0RkJe" # Starboy - The Weeknd
)
# Collecting album data for a given year via function
get_album_data <- function(album_ids, token) {
album_chunks <- split(album_ids, ceiling(seq_along(album_ids) / 50))
map_dfr(album_chunks, function(ids_chunk) {
req <- request("https://api.spotify.com/v1/albums") |>
req_url_query(ids = paste(ids_chunk, collapse = ",")) |>
req_headers(Authorization = paste("Bearer", token))
resp <- req_perform(req)
content <- resp_body_json(resp, simplifyVector = FALSE)
map_dfr(content$albums, function(album) {
tibble(
id = album$id,
name = album$name,
release_date = album$release_date,
artists = paste(album$artists, collapse = ", "),
)
})
})
}
# Assigning data from previous function into a table
album_data_2024 <- get_album_data(album_ids_2024, token)
get_album_tracks <- function(album_id, token) {
url <- paste0("https://api.spotify.com/v1/albums/", album_id, "/tracks")
req <- GET(
url,
add_headers(Authorization = paste("Bearer", token))
)
content <- content(req, "parsed", simplifyVector = FALSE)
table <- map_dfr(content$items, function(track) {
tibble(
album_id = album_id,
track_id = track$id,
track_name = track$name,
track_number = track$track_number,
track_artists = paste(map_chr(track$artists, "name"), collapse = ", "),
track_duration_ms = track$duration_ms,
track_explicit = track$explicit
)
})
}
all_albums <- map_dfr(album_ids_2018, get_album_tracks, token = token)
# Merge track data with artist names
#all_tracks <- left_join(all_tracks, album_data |> select(artist_id, artist_name), by = "artist_id")
all_tracks |>
filter(artist_name == "Taylor Swift") |>
plot_ly(
x = ~reorder(track_name, popularity),
y = ~popularity,
type = 'bar',
color = ~explicit,
colors = c('blue', 'red'),
text = ~paste("Track:", track_name,
"\nArtist:", artist_name,
"\nPopularity:", popularity,
"\nExplicit:", explicit),
hoverinfo = "text") |>
layout(title = "Top Tracks by Popularity",
xaxis = list(title = "Track Name", tickangle = -45),
yaxis = list(title = "Popularity"))
Revealed: The Top Artists, Songs, Albums, Podcasts, and Audiobooks of 2024 (https://newsroom.spotify.com/2024-12-04/top-songs-artists-podcasts-audiobooks-albums-trends-2024/)
Spotify Web API (https://developer.spotify.com/documentation/web-api)